package amqplib

import (
	"errors"
	"fmt"
	"net"
	"time"

	"github.com/brotherbaby/jinzhugo/logger"
	"github.com/streadway/amqp"
)

func InitConnectionPool(config MQConnectorConfig, poolConfig ConnectionPoolConfig) (*ConnectionPool, error) {
	if poolConfig.maxIdle <= 0 || poolConfig.maxActive <= 0 || poolConfig.maxIdle > poolConfig.maxActive {
		return nil, errors.New("invalid pool configuration")
	}

	pool := &ConnectionPool{
		config:       config,
		pool:         make(chan *amqp.Connection, poolConfig.maxActive),
		maxIdle:      poolConfig.maxIdle,
		maxActive:    poolConfig.maxActive,
		idleTimeout:  poolConfig.idleTimeout,
		waitConnTime: poolConfig.waitConnTime,
	}

	// 预创建初始连接
	for i := 0; i < poolConfig.maxIdle; i++ {
		conn, err := pool.createConnection()
		if err != nil {
			logger.Warn("Failed to pre-create connection: %v", err)
			break
		}
		pool.pool <- conn
	}

	return pool, nil
}

// 创建新连接
func (p *ConnectionPool) createConnection() (*amqp.Connection, error) {
	conn, err := amqp.DialConfig(p.formatConnUrl(), amqp.Config{
		Heartbeat: time.Duration(p.config.Heartbeat) * time.Second,
		Dial: func(network, addr string) (net.Conn, error) {
			return net.DialTimeout(network, addr, time.Duration(p.config.Timeout)*time.Second)
		},
	})

	if err != nil {
		logger.Error("Failed to create connection: %v", err)
		return nil, err
	}

	return conn, nil
}

// 获取连接
func (p *ConnectionPool) GetConn() (*amqp.Connection, error) {
	p.lock.Lock()
	defer p.lock.Unlock()

	if p.isClosed {
		return nil, errors.New("connection pool is closed")
	}

	// 如果有空闲连接，直接获取
	if len(p.pool) > 0 {
		conn := <-p.pool
		// 检查连接是否有效
		if p.isConnectionValid(conn) {
			return conn, nil
		}
		// 连接无效，关闭并创建新连接
		conn.Close()
		p.activeCount--
	}

	// 没有空闲连接，检查是否可以创建新连接
	if p.activeCount < p.maxActive {
		conn, err := p.createConnection()
		if err != nil {
			return nil, err
		}
		p.activeCount++
		return conn, nil
	}

	// 已达到最大连接数，等待空闲连接
	logger.Info("Waiting for available connection...")
	timeout := time.NewTimer(p.waitConnTime)
	defer timeout.Stop()

	select {
	case conn := <-p.pool:
		if p.isConnectionValid(conn) {
			return conn, nil
		}
		conn.Close()
		p.activeCount--
		return p.GetConn() // 递归重试
	case <-timeout.C:
		return nil, errors.New("timeout waiting for connection")
	}
}

// 释放连接回池
func (p *ConnectionPool) Release(conn *amqp.Connection) {
	if conn == nil {
		return
	}

	p.lock.Lock()
	defer p.lock.Unlock()

	if p.isClosed {
		conn.Close()
		return
	}

	// 检查连接是否有效
	if !p.isConnectionValid(conn) {
		conn.Close()
		p.activeCount--
		return
	}

	// 如果池已满或连接已超时，关闭连接
	if len(p.pool) >= p.maxIdle {
		conn.Close()
		p.activeCount--
		return
	}

	// 放回池中
	p.pool <- conn
}

// 关闭连接池
func (p *ConnectionPool) Close() {
	p.lock.Lock()
	defer p.lock.Unlock()

	if p.isClosed {
		return
	}

	p.isClosed = true

	// 关闭所有连接
	close(p.pool)
	for conn := range p.pool {
		conn.Close()
	}
	p.activeCount = 0
}

// 检查连接是否有效
func (p *ConnectionPool) isConnectionValid(conn *amqp.Connection) bool {
	if conn == nil || conn.IsClosed() {
		return false
	}

	// 简单的连接检查
	ch, err := conn.Channel()
	if err != nil {
		logger.Warn("Connection check failed: %v", err)
		return false
	}
	defer ch.Close()

	return true
}

// 格式化连接URL
func (p *ConnectionPool) formatConnUrl() string {
	connDSN := fmt.Sprintf("amqp://%s:%s@%s:%d/%s",
		p.config.User, p.config.Password, p.config.Host, p.config.Port, p.config.Path)
	logger.Info(fmt.Sprintf("Connecting to: amqp://%s:***@%s:%d/%s",
		p.config.User, p.config.Host, p.config.Port, p.config.Path))
	return connDSN
}

// 设置获取连接的等待时间
func (p *ConnectionPool) SetWaitConnTime(timeout time.Duration) {
	p.waitConnTime = timeout
}
